import React, {Component} from 'react'
import {MarkdownPreview} from 'react-marked-markdown';
// import py1_1 from '../static/py1_1.md'
// import marked from 'marked';

class Py28 extends Component {
    constructor(props) {
        super(props);
        this.state = {
           value: `
本章内容放在最后来介绍还是比较合适的。到现在为止，我们已经在自己的电脑上通过命
令行运行了所有的 Pyhton 程序。当然，你可能也安装了 MySQL，尝试真实的服务器环境。
但是这和实际的服务器还是不一样的。正如一句谚语所说：“如果你喜欢某个东西，就放
开手。”

这一章我们将介绍几种方法，让程序在不同的机器上运行，或者在你的电脑上用不同的 IP
地址运行。你可能打算放弃这一章，因为你现在还不需要这些内容，但是你可能会感到惊
讶，自己原来已经拥有非常容易上手的工具了（比如一些付费的 VPS 或云计算资源），而
且当你停止在自己的笔记本上运行 Python 爬虫后，生活会变得更加轻松。

> 14.1　为什么要用远程服务器

虽然使用远程服务器看起来可能更像是在启动一个供广大用户使用的网络应用时所采取的
必然步骤，但我们为个人目的建立的工具通常都必须在本地运行。启用远程平台的人通常
有两个目的：对更大计算能力和灵活性的需求，以及对可变 IP 地址的需求。

> 14.1.1　避免IP地址被封杀

建立网络爬虫的第一原则是：所有信息都可以伪造。你可以用非本人的邮箱发送邮件，通
过命令行自动化鼠标的行为，或者通过 IE5.0 浏览器耗费网站流量来吓唬网管。
但是有一件事情是不能作假的，那就是你的 IP 地址。任何人都可以用这个地址给你写信：
“美国华盛顿特区宾夕法尼亚大道西北 1600 号，总统，邮编 20500。”但是，如果这封信是
从新墨西哥州的阿尔伯克基市发来的，那么你肯定可以确信给你写信的不是美国总统。 

阻止网站被采集的注意力主要集中在识别人类与机器人的行为差异上面。封杀 IP 地址这种
矫枉过正的行为，就好像是农民不靠喷农药给庄稼杀虫，而是直接用火烧彻底解决问题。
它是最后一步棋，不过是一种非常有效的方法，只要忽略危险 IP 地址发来的数据包就可以
了。但是，使用这种方法会遇到以下几个问题。
* IP 地址访问列表很难维护。虽然大多数大型网站都会用自己的程序自动管理 IP 地址访
问列表（机器人封杀机器人），但是至少需要人偶尔检查一下列表，或者至少要监控问
题的增长。
* 因为服务器需要根据 IP 地址访问列表去检查每个准备接收的数据包，所以检查接收数
据包时会额外增加一些处理时间。多个 IP 地址乘以海量的数据包更会使检查时间指数
级增长。为了降低处理时间和处理复杂度，管理员通常会对 IP 地址进行分组管理并制
定相应的规则，比如如果这组 IP 中有一些危险分子就“把这个区间的所有 256 个地址
全部封杀”。于是产生了下一个问题。
* 封杀 IP 地址可能会导致意外后果。例如，当我还在美国麻省欧林工程学院读本科的时
候，有个同学写了一个可以在 http://digg.com/ 网站（在 Reddit 流行之前大家都用 Digg）
上对热门内容进行投票的软件。这个软件的服务器 IP 地址被 Digg 封杀，导致整个网站
都不能访问。于是这个同学就把软件移到了另一个服务器上，而 Digg 自己却失去了许
多主要目标用户的访问量。

虽然有这些缺点，但封杀 IP 地址依然是一种十分常用的手段，服务器管理员用它来阻止可
疑的网络爬虫入侵服务器。

> 14.1.2　移植性与扩展性

有一些任务想通过个人电脑连网完成会十分困难。即使你并不想给任何一个网站增加负
载，但是如果你会从一堆网站里收集数据，也会需要更快的网速以及更多存储空间。

另外，自己电脑上的计算资源释放之后，你就可以做很多更重要事情啦（玩魔兽，看电
影，LOL）。你也不用担心电费和网速了（在星巴克启动你的应用，合上笔记本离开，每
件事情都可以安全地运行），你也可以在任何有网络连接的地方收集数据。

如果你的一个应用需要非常大的计算能力，亚马逊 AWS 的一个超大计算实例也不能满足
你的需求，那么你可以看看分布式计算（distributed computing）。这种方法可以让多个机器
并发执行来完成你的任务。一个简单的例子是你可以用一台机器来采集一些网站，再用另
一台机器采集另一些网站，最后在把所有的结果存储在同一个数据库里。

当然，前几章的例子很多都是在重复 Google 搜索干的事情，但是没有几个程序可以达到
Google 搜索的运行规模。分布式计算是计算机科学中的一个庞大领域，超出了本书的介绍
范围。但是，学习如何让你的程序在远程服务器执行是基本前提，学会之后你一定对当今
计算机的能力感到无比惊讶。

> 14.2　Tor代理服务器

洋葱路由（The Onion Router）网络，常用缩写为 Tor，是一种 IP 地址匿名手段。由网络志
愿者服务器构建的洋葱路由器网络，通过不同服务器构成多个层（就像洋葱）把客户端包
在最里面。数据进入网络之前会被加密，因此任何服务器都不能偷取通信数据。另外，虽
然每一个服务器的入站和出站通信都可以被查到，但是要想查出通信的真正起点和终点，
必须知道整个通信链路上所有服务器的入站和出站通信细节，而这基本是不可能实现的。

Tor 是人权工作者和政治避难人员与记者通信的常用手段，得到了美国政府的大力支持。
当然，它经常也被用于非法活动，所以也是政府盯防的目标（虽然目前盯防得并不是很
成功）。

#### Tor 匿名的局限性

虽然我们在本书中用 Tor 的目的是改变 IP 地址，而不是实现完全匿名，但有
必要关注一下 Tor 匿名方法的能力和不足。

虽然 Tor 网络可以让你访问网站时显示的 IP 地址是一个不能跟踪到你的 IP
地址，但是你在网站上留给服务器的任何信息都会暴露你的身份。例如，你
登录 Gmail 账号后再用 Google 搜索，那些搜索历史就会和你的身份绑定在
一起。

另外，登录 Tor 的行为也可能让你的匿名状态处于危险之中。2013 年 12 月，
一个哈佛大学本科生想逃避期末考试，就用一个匿名邮箱账号通过 Tor 网络
给学校发了一封炸弹威胁信。结果哈佛大学的 IT 部门通过日志查到，在炸
弹威胁信发来的时候，Tor 网络的流量只来自一台机器，而且是一个在校学
生注册的。虽然他们不能确定流量的最初源头（只知道是通过 Tor 发送的），
但是作案时间和注册信息证据充分，而且那个时间段内只有一台机器是登录
状态，这就有充分理由起诉那个学生了。

登录 Tor 网络不是一个自动的匿名措施，也不能让你进入互联网上任何区
域。虽然它是一个实用的工具，但是用它的时候一定要谨慎、清醒，并且遵
守道德规范

在 Python 里使用 Tor，需要先安装运行 Tor，下一节将介绍。Tor 服务很容易安装和开启。
只要去 Tor 下载页面（https://www.torproject.org/download/download）下载并安装，打开后
连接就可以。不过要注意，当你用 Tor 的时候网速会变慢。这是因为代理有可能要先在全
世界网络上转几次才到目的地！

#### PySocks

PySocks 是一个非常简单的 Python 代理服务器通信模块，它可以和 Tor 配合使用。你可以
从它的网站（https://pypi.python.org/pypi/PySocks）上下载，或者使用任何第三方模块管理
器安装。

这个模块的用法很简单。示例代码如下所示。运行的时候，Tor 服务必须运行在 9150 端口
（默认值）上：
    
    import socks
    import socket
    from urllib.request import urlopen

    socks.set_default_proxy(socks.SOCKS5, "localhost", 9150)
    socket.socket = socks.socksocket
    print(urlopen('http://icanhazip.com').read())
   
网站 http://icanhazip.com/ 会显示客户端连接的网站服务器的 IP 地址，可以用来测试 Tor 是
否正常运行。当程序执行之后，显示的 IP 地址就不是你原来的 IP 了。

如果你想在 Tor 里面用 Selenium 和 PhantomJS，不需要 PySocks，只要保证 Tor 在运行，然
后增加 service_args 参数设置代理端口，让 Selenium 通过端口 9150 连接网站就可以了：
   
    from selenium import webdriver
    service_args = [ '--proxy=localhost:9150', '--proxy-type=socks5', ]
    driver = webdriver.PhantomJS(executable_path='<path to PhantomJS>',service_args=service_args)

    driver.get("http://icanhazip.com")
    print(driver.page_source)
    driver.close()
    
和之前一样，这个程序打印的 IP 地址也不是你原来的，而是你通过 Tor 客户端获得的 IP
地址。

> 14.3　远程主机

一旦你使用信用卡，完全的匿名效果就消失了，即便如此，你还是可以把网络爬虫放在远
程主机（Remote Hosting）上动态地改善它们的运行速度。这是因为你不仅可以自由购买
服务器的使用时间，使用更强大的机器，而且网络连接也不需要在到达访问目的地之前在
Tor 网络中长途跋涉。

> 14.3.1　从网站主机运行

如果你拥有个人网站或公司网站，那么你可能已经知道如何使用外部服务器运行你的网络
爬虫了。即使是一些相对封闭的网络服务器，没有可用的命令行接入方式，你也可以通过
网页界面对程序进行控制。

如果你的网站部署在 Linux 服务器上，应该已经运行了 Python。如果你用的是 Windows 服
务器，可能就没那么幸运了；你需要仔细检查一下 Python 有没有安装，或者问问网管可不
可以安装。

大多数小型网络主机都会提供一个软件叫 cPanel，提供网站管理和后台服务的基本管理功
能和信息。如果你接入了 cPanel，就可以设置 Python 在服务器上运行——进入“Apache
Handlers”然后增加一个 handler（如还没有的话）：
   
    Handler: cgi-script
    Extension(s): .py
  
这会告诉服务器所有的 Python 脚本都将作为一个 CGI 脚本运行。CGI 就是通用网关接口
（Common Gateway Interface），是可以在服务器上运行的任何程序，会动态地生成内容并显
示在网站上。把 Python 脚本显式地定义成 CGI 脚本，就是给服务器权限去执行 Python 脚
本，而不只是在浏览器上显示它们或者让用户下载它们。

写完 Python 脚本后上传到服务器，然后把文件权限设置成 755，让它可执行。通过浏览器
找到程序上传的位置（也可以写一个爬虫来自动做这件事情）就可以执行程序。如果你担
心在公共领域执行脚本不安全，可以采取以下两种方法。
* 把脚本存储在一个隐晦或深层的 URL 里，确保其他 URL 链接都不能接入这个脚本，这
样可以避免搜索引擎发现它。
* 用密码保护脚本，或者在执行脚本之前用密码或加密令牌进行确认。

确实，通过这些原本主要是用来显示网站的服务运行 Python 脚本有点儿复杂。比如，你可
能会发现网络爬虫运行时网站的加载速度变慢了。其实，在整个采集任务完成之前页面都
是不会加载的（得等到所有“print”语句的输出内容都显示完）。这可能会消耗几分钟，几
小时，甚至永远也完成不了，要看程序的具体情况了。虽然它最终一定能完成任务，但是
可能你还想看到实时的结果，这样就需要一台真正的服务器了。

>  14.3.2　从云主机运行
以前，程序员会为了在计算机上运行或者存储自己的程序而付费。个人电脑发明之后，这
种事情似乎没必要了——人们可以直接在自己的电脑上写程序并运行。现在，应用程序的
计算需求已经完全超越了微处理器的发展速度，于是程序员又开始为计算能力付费了。

但是，这次用户不再为单个物理机器的计算能力付费，而是为多个机器共同的计算能力付
费。这种云状计算系统的计算能力可以按使用时间进行付费。例如，当客户计算的低成本
比即时性更重要时，亚马逊的 EC2 允许用户使用“竞价型实例”（spot instance），可以先
竞价再使用云计算服务。

计算实例还可以进行定制，也可以根据应用程序的实际需求进行设置，选项有“高内
存”“快速计算”“大容量存储”。虽然网络爬虫不需要很多内存，但是你可能需要较大的
存储空间或快速的计算能力来实现爬虫的更多功能。如果你要做大量的自然语言处理、
OCR 或者路径查找（就像“维基百科六度分隔理论”问题）之类的工作，选择“快速计
算”实例就可以。如果你要采集大量数据，存储许多文件，或者进行大数据分析，可能就
需要用带大容量存储的计算实例了。

虽然云计算的花费可能是无底洞，但是写到这里的时候，启动一个计算实例最便宜只要每
小时 1.3 美分（亚马逊 EC2 的 micro 实例，其他实例会更贵），Google 最便宜的计算实例
是每小时 4.5 美分，最少需要用 10 分钟。考虑计算能力的规模效应，从大公司买一个小型
的云计算实例的费用，和自己买一台专业实体机的费用应该差不多——不过用云计算不需
要雇人去维护设备。

显然，一步一步设置和运行云计算实例的教程超出了本书介绍范围，不过你自己其实不需
要这类教程。亚马逊和 Google（还有不计其数的小公司）的云计算产品正在激烈竞争，它
们会尽力把新实例创建的步骤做到最简单，填个应用名称，设置一下信用卡信息就可以
了。写到这里的时候，亚马逊和 Google 还为新用户提供了价值几百美元的免费计算时间。

设置好计算实例之后，你就有了新 IP 地址、用户名，以及可以通过 SSH 进行实例连接的
公私密钥了。后面要做的每件事情，都应该和你在实体服务器上干的事情一样了——当
然，你不需要再担心硬件维护，也不用运行复杂多余的监控工具了。

> 14.4　其他资源

很多年以前，“在云端”运行基本上是那些既懂理论又具有服务器运维经验的人们之间的
高谈阔论。但是今天，由于云计算技术的不断普及，以及云计算供应商之间的竞争，云计
算工具已经有了极大的改善。

如果你想建立规模更大或更复杂的爬虫，在创建云计算平台以收集和存储数据时，可能还
需要一些参考资料。

Marc Cohen、Kathryn Hurley 和 Paul Newson 合 著 的 Google Compute Engine（http://shop.oreilly.com/product/0636920028888.do）是通过 Python 和 JavaScript 使用 Google 云计算平台
的第一手资料。书中不仅介绍了 Google 的用户界面，还介绍了命令行和脚本工具，可以
让你的应用获取更大的灵活性。

如果你更喜欢亚马逊，Mitch Garnaat 的 Python and AWS Cookbook（http://shop.oreilly.com/
product/0636920020202.do）是一本非常实用的手册，可以让你顺利启动 AWS 服务，还会
告诉你如何创建并运行一个可扩展的应用。

> 14.5　勇往直前

网络一直在不断地变化。那些给我们带来了图像、视频、文字和其他数据文件的计算机
技术也在不断地升级和改进。如果想紧跟技术潮流，采集互联网数据的技术就需要随机
应变。

本书未来的版本可能会完全忽略 JavaScript，它已是一种过时的、极少用的技术了，而重
点关注用 HTML8 实现页面。但是，采集网站内容的基本思路和一般方法是不会改变的。
无论现在还是将来，遇到一个网络数据采集项目时，你都应该问问自己以下几个问题。
* 我需要回答或要解决的问题是什么？
* 什么数据可以帮助我，它们都在哪里？
* 网站是如何展示数据的？我能准确地识别网站代码中包含信息的部分吗？
* 该如何定位这些数据并获取它们？
* 为了让数据更实用，我应该做怎样的处理和分析？
* 怎样才能让采集过程更好，更快，更稳定？

总之，你不仅需要掌握如何使用本书中介绍的工具，还要知道如何把它们有效地组合起来
解决问题。有时，数据格式很规范，比较容易获取，用一个简单的爬虫就搞定了。有时，
你可能需要仔细地思考一番才能解决。

例如，在第 10 章里，我首先用 Selenium 获取在亚马逊图书预览页面中通过 Ajax 加载的图
片，然后再用 Tesseract 读取图片，识别里面的文字。在“维基百科六度分隔”问题中，我
先用正则表达式实现爬虫，把维基词条链接信息存储到数据库，然后用有向图算法寻找词
条凯文 ·贝肯与词条埃里克· 艾德尔之间最短的链接路径。

在使用自动化技术采集互联网数据时，其实很少遇到完全无法解决的问题。记住一点就
行：互联网其实就是一个用户界面不太友好的超级 API。
    
           
           `,
        };
      }
    render() {
        return (
            <div >
                {/* 111111111111111
                <Py112 /> */}
                <MarkdownPreview value={this.state.value}/>
            </div>
        )
    }
}

export default Py28